<template>
	<view class="y-form" :class="radius">
		<view class="form-title" v-show="title">{{ title }}</view>
		<view
			:style="{ display: i.block ? 'block' : 'flex' }"
			class="item"
			:class="errorPrompt[i.key] && 'error-input'"
			v-for="(i, key) in _keys"
			:key="(i.key || key)+'0'"
			v-if="!i.hide"
		>
			<view :class="i.required ? 'required' : ''" style="display: flex;justify-content: space-between;white-space: nowrap;">
				<text>{{ i.lable }}</text>
				<Expand :render="i.lable_render" :keys="i" :value="value" @upData="upData" @input="updateValue($event, i.key, key)"></Expand>
			</view>
			<view style="display: flex;flex: 1;width: 100%;flex-direction: row;flex-wrap: wrap;">
				<template v-if="!i.slot">
					<component
						class="form-el"
						:style="i.style"
						@childChange="childChange($event, i.key)"
						:is="i.type"
						:value="value[i.key]"
						:keys="i"
						@input="updateValue($event, i.key, key)"
						@change="(i.change || (e => e))($event)"
					></component>
					<Expand :render="i.form_render || i.render" :keys="i" :value="value" @upData="upData" @input="updateValue"></Expand>
					<view
						class="formicon form-guanbi1"
						v-if="!i.required && value[i.key] && !closeBool.includes(i.type) && !i.hideClear"
						@click="updateValue('', i.key, key)"
					></view>
				</template>
				<template v-else>
					<slot :name="i.slot" :keys="i"></slot>
				</template>
			</view>
			<view class="error-prompt" v-if="errorPrompt[i.key]">{{ errorPrompt[i.key] }}</view>
		</view>
		<view style="width: 100%;word-break: break-all;"><slot></slot></view>
		<view style="margin-top: 20rpx;display: flex;justify-content: center;align-items: center;" v-if="_keys.length">
			<slot name="submit" :verifi="verifi">
				<a-button style="width: 40vmin;" @click="verifi()">{{ submitText }}</a-button>
			</slot>
		</view>
	</view>
</template>

<script>
import Expand from './expand.js';
import yInput from './y-input.vue';
import yPicker from './y-picker.vue';
import form from './formValidation.js';
import yUpload from './y-upload';
import yTextarea from './y-textarea.vue';
import yRadio from './y-radio.vue';
export default {
	name: 'yForm',
	components: {
		Expand,
		yInput,
		yPicker,
		yUpload,
		yTextarea,
		yRadio,
		number:yInput,
		password:yInput
	},
	props: {
		keys: {
			type: Array,
			default() {
				return [];
			}
		},
		value: {},
		radius: '',
		title: '',
		row: {
			type: Number,
			default: 1
		},
		submitText: {
			type: String,
			default: '提交'
		}
	},
	mounted() {
		this.$emit('render', this);
	},
	data() {
		return {
			errorPrompt: {},
			closeBool: ['yUpload', 'yChange', 'yRadio', 'yCheckbox']
		};
	},
	computed: {
		_keys() {
			return this.keys.map(x => {
				let o = this.value;
				//初始化
				if (typeof x.init === 'function' && this.value[x.key] === undefined) {
					o = x.init(o, x) || o;
					this.$emit('input', o);
				}
				x.form_hide && (x.hide = x.form_hide);
				typeof x.hide === 'function' && (x.hide = x.hide(o, x));
				typeof x.form_hide === 'function' && (x.form_hide = x.form_hide(o, x));
				typeof x.lable === 'function' && (x.lable = x.lable(o, x));
				const { rules = {}, ...res } = x;
				if (x.type === 'yUpload') {
					rules.rule = [...(rules.rule || []), 'uploading'];
					rules.msg = [...(rules.msg || []), '未上传完成'];
				}
				return {
					required: (rules.rule || []).includes('required'),
					rules,
					...res
				};
			});
		},
		keysObject() {
			return this.keys.reduce((o, x) => {
				o[x.key] = x;
				return o;
			}, {});
		}
	},
	methods: {
		//render 函数 事件更新 数据 并全局验证
		upData(e = {}) {
			let value = { ...this.value, ...e };
			//验证
			this.verifi(Object.keys(e));
			//更新数据
			this.$emit('input', value);
		},
		//动态 子表单 处理

		childChange(...g) {
			// console.log(g);
		},
		//通过key查找
		async updateValue(e, key, index) {
			//当前项
			const { rules = {}, change, ...item } = index instanceof Object ? { ...index, ...this.keysObject[key] } : this.keysObject[key];
			const value = {
				...this.value
			};
			value[key] = e;
			typeof change === 'function' && (await change(e, item, value));
			this.$emit('change', value);
			return form
				.validation(value, [
					{
						...rules,
						name: key
					}
				])
				.then(msg => {
					this.$emit('input', value);
					this.$set(this.errorPrompt, key, msg);
				});
		},
		change(...e) {
			this.$emit('change', ...e);
		},
		verifi(keys, value = this.value) {
			if (typeof keys === 'string') {
				keys = keys.split(',').map(key => this.keysObject[key]);
			}
			return Promise.all(
				(keys || this._keys)
					.map((x, index) => {
						if (x.hide) return '';
						return form.validation(value, [{ ...(x.rules || {}), name: x.key }]).then(msg => {
							this.$set(this.errorPrompt, x.key, msg);
							return msg;
						});
					})
					.filter(x => {
						if (x) return x;
					})
			).then((msg = []) => {
				let _msg = msg.join('')
					? false
					: {
							...this.value
					  };
				Array.isArray(keys) || this.$emit('submit', _msg);
				typeof keys === 'function' && e(_msg);
				return Promise.reject(msg);
				// if(_msg){
				// 	this.$emit('submit',_msg);
				// 	typeof e === "function" && e(_msg);
				// }else{
				// 	return Promise.reject(msg);
				// }
			});
		}
	}
};
</script>

<style lang="scss">
@import url(//at.alicdn.com/t/font_1867189_9w3btv3gxlc.css);
@import url(./error.css);

.y-form {
	font-size: 16px;
	padding: 12px;
	background-color: #fff;

	.form-title {
		font-size: 32rpx;
		font-weight: 700;
		line-height: 2em;
		height: 2.4em;
		white-space: nowrap;
		position: relative;
		&::after {
			content: '';
			position: absolute;
			left: 0;
			bottom: 0;
			right: 0;
			height: 1px;
			background-color: rgba(0, 0, 0, 0.2);
			transform: scaleY(0.2);
		}
	}
	&.radius {
		border-radius: 16rpx;
		overflow: hidden;
		margin: 16px;
		box-shadow: 0 0 26rpx 0 rgba(0, 0, 0, 0.3);
	}

	.item {
		display: flex;
		font-size: inherit;
		padding-top: inherit;
		padding-bottom: inherit;
		position: relative;
		text-align: left;
		flex-direction: row;
		flex-wrap: wrap;

		.form-el {
			flex: 1;
			text-align: right;
		}

		&::after {
			content: '';
			position: absolute;
			bottom: 0;
			left: 0;
			right: 0;
			height: 1px;
			background-color: rgba(0, 0, 0, 0.2);
			transform: scaleY(0.2);
		}
	}

	.required {
		position: relative;
		&::before {
			content: '*';
			font-size: 0.8em;
			position: absolute;
			color: red;
			transform: translateX(-100%);
		}
	}

	.form-guanbi1 {
		border-radius: 50%;
		background-color: rgba(0, 0, 0, 0.1);
		height: 1em;
		width: 1em;
		line-height: 1em;
		margin-left: 20rpx;
	}
	.submit-btn {
		border-radius: 3000px;
		width: 15em;
		margin-top: 20rpx;
		box-shadow: 0 0 20rpx 0 rgba(0, 0, 0, 0.3);
	}
}
</style>
